package com.nebrija.riif.model;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

public class RealTimelineExecution extends TimerTask implements TimelineExecution {

	private boolean running = false; 
	
	private Timeline timeline;
	private Calendar initialTime;
	private Calendar stateTime;
	private Calendar endTime;
	
	private State curState;
	Timer t = new Timer();
	
	public RealTimelineExecution(Timeline timeline) {
		this.timeline = timeline;
	}

	@Override
	public Double getTimeSinceLastTransition(TimeStrings ts) {
		if(stateTime==null){
			return null;
		}
		Calendar now = Calendar.getInstance();
		int field = TimeStrings.timeStringsToCalendar(ts);
		long msdiff = now.getTimeInMillis() - stateTime.getTimeInMillis();
		double finalVal = 0;
		switch(field){
			case Calendar.MONTH: 
								finalVal = now.get(Calendar.MONTH) - stateTime.get(Calendar.MONTH);
								finalVal+= 12*(now.get(Calendar.YEAR) - stateTime.get(Calendar.YEAR));
								break;
			case Calendar.YEAR: 
								finalVal= now.get(Calendar.YEAR) - stateTime.get(Calendar.YEAR);
								break;
			case Calendar.DATE:
								finalVal = (double)msdiff/(1000*60*60*24);
								break;
			case Calendar.HOUR:
								finalVal = (double)msdiff/(1000*60*60);
								break;
			case Calendar.MINUTE:
								finalVal = (double)msdiff/(1000*60);
								break;
			case Calendar.SECOND:
								finalVal = (double)msdiff/1000;
								break;
			default:
								finalVal = msdiff;
		}
		return finalVal;
	}

	@Override
	public State getCurrentState() {
		return curState;
	}

	@Override
	public void runTimeline() {
		if(running){
			System.out.println("Error. The timeline is already running");
		}
		running = true;
		curState = timeline.getInitialState();
		initialTime = Calendar.getInstance();
		endTime = (Calendar) initialTime.clone();
		this.scheduleExecution();
	}

	@Override
	public void run() {
		if(!running){ //Execution was stopped
			return;
		}
		//Transition to next state
		String stName = curState.getNextStateName();
		if(stName==null){
			running = false;
			return;
		}
		System.out.println("Performing transition to state " +stName+ " in timeline " + timeline.getName());
		curState = (State) timeline.getElement(stName);
		this.scheduleExecution();
	}
	
	protected void scheduleExecution(){
		if (curState==null){
			return;
		}
		ValueTimeUnit vtu = curState.getDuration();
		stateTime=(Calendar)endTime.clone();
		endTime.add(TimeStrings.timeStringsToCalendar(vtu.getTimeUnit()),(int)vtu.getValue());
		t.schedule(new StateMigrationTask(this), endTime.getTime());
	}

	class StateMigrationTask extends TimerTask{
		RealTimelineExecution rtl;
		public StateMigrationTask(RealTimelineExecution rtl) {
			this.rtl = rtl;
		}
		
		@Override
		public void run() {
			rtl.run();	
		}
		
	}

	@Override
	public void stop() {
		running=false;
		try{
			t.cancel();
			t.purge();
		}catch(Exception e){			
		}
		
	}
	
	@Override
	public Double getTimeSince(Calendar cal, TimeStrings ts) {
		Calendar now = Calendar.getInstance();
		int field = TimeStrings.timeStringsToCalendar(ts);
		long msdiff = now.getTimeInMillis() - cal.getTimeInMillis();
		double finalVal = 0;
		switch(field){
			case Calendar.MONTH: 
								finalVal = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);
								finalVal+= 12*(now.get(Calendar.YEAR) - cal.get(Calendar.YEAR));
								break;
			case Calendar.YEAR: 
								finalVal= now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
								break;
			case Calendar.DATE:
								finalVal = (double)msdiff/(1000*60*60*24);
								break;
			case Calendar.HOUR:
								finalVal = (double)msdiff/(1000*60*60);
								break;
			case Calendar.MINUTE:
								finalVal = (double)msdiff/(1000*60);
								break;
			case Calendar.SECOND:
								finalVal = (double)msdiff/1000;
								break;
			default:
								finalVal = msdiff;
		}
		return finalVal;
	}
	
}
